Skip to main content

Transactions – Go SDK Reference

Overview

The Go SDK exposes a small set of types and methods to:

  • Load a wallet
  • Open a transaction session against a node
  • Build, sign, and submit a transaction
  • Inspect the resulting transaction and its status

This page documents those core types and methods for quick reference. Tutorials and end-to-end examples will live in separate pages.


Imports

import (
"github.com/ULedgerInc/go-sdk/pkg/wallet"
"github.com/ULedgerInc/go-sdk/pkg/transaction"
)

Wallet loading

wallet.FromJson

func FromJson(raw string, passphrase string) (UL_Wallet, error)

Loads an encrypted or plain wallet from a JSON string and returns a UL_Wallet instance, which is then used to sign transactions.

Used in your CLI:

w, err := wallet.FromJson(rawWallet, passphrase)
if err != nil {
return fmt.Errorf("error loading wallet: %w", err)
}
fmt.Printf("Loaded wallet: %+v\n", w)

The returned UL_Wallet exposes:

  • Address – the wallet’s address
  • GetKey() – returns the underlying key, used to sign commitments and discover KeyType.

Transaction session

Type: UL_TransactionSession

type UL_TransactionSession struct {
nodeEndpoint string
suggestor string
wallet wallet.UL_Wallet
}

A transaction session encapsulates:

  • The node endpoint (base URL of the node)
  • The suggestor (node ID used for the transaction)
  • The wallet used to sign the transaction

You typically obtain it via the constructor:

transaction.NewUL_TransactionSession

func NewUL_TransactionSession(
nodeEndpoint string,
wallet wallet.UL_Wallet,
) (UL_TransactionSession, error)

What it does:

  1. Calls GET {nodeEndpoint}/health to obtain node metadata (nodeId, version, chains info).
  2. Calls GET {nodeEndpoint}/blockchains to ensure at least one blockchain is available.
  3. Returns a UL_TransactionSession with:
    • nodeEndpoint set
    • suggestor set to the node ID
    • wallet set to the provided UL_Wallet

Example (simplified from your CLI):

session, err := transaction.NewUL_TransactionSession(
testConfig.NodeEndpoints[n],
*wallet,
)
if err != nil {
return fmt.Errorf("error creating transaction session: %w", err)
}

(*UL_TransactionSession).GenerateTransaction

func (session *UL_TransactionSession) GenerateTransaction(
input ULTransactionInput,
) (ULTransaction, error)

High-level responsibilities:

  1. Populate metadata on ULTransactionInput:

    • Sets input.Suggestor to session.suggestor
    • Sets input.SenderTimestamp to current UTC time
    • For non-CREATE_WALLET and non-ALTER_WALLET payloads, sets input.From to session.wallet.Address
    • Sets input.KeyType based on session.wallet.GetKey().GetType()
  2. Compute commitment & payload root:

    • For DEPLOY_SMART_CONTRACT, UPGRADE_SMART_CONTRACT, TX_CREATE_WALLET, TX_ALTER_WALLET:

      • Calls input.GetUnboundCommitment(hasher)
      • Sets input.PayloadRoot to the returned root (hex-encoded)
    • For other transaction types:

      • Calls input.GetSignatureCommitment(hasher, true) to build a Merkle commitment
      • Calls input.HashSignatureCommitment(hasher, commitment) to get the commitment hash
      • Sets input.PayloadRoot to the Merkle payload root
  3. Sign the commitment:

    • Signs the commitment with session.wallet.GetKey().SignData(commitment)
    • Sets input.SenderSignature with the hex-encoded signature
  4. Submit to the node:

    • POSTs JSON to:

      POST {nodeEndpoint}/blockchains/{blockchainId}/transactions
    • Expects 200 OK or 201 Created

    • Unmarshals the response into a ULTransaction

Example (from your CLI):

tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("error generating transaction: %w", err)
}

if tx.TransactionId == "" {
return fmt.Errorf("generated transaction has empty transaction ID")
}

fmt.Printf("Transaction: %+v\n", tx)

Transaction types

ULTransactionInput

Fields used to create a transaction:

type ULTransactionInput struct {
BlockchainId string `json:"blockchainId"`
To string `json:"to"`
From string `json:"from"`
Payload string `json:"payload"`
SenderSignature string `json:"senderSignature"`
PayloadType string `json:"payloadType"`
Suggestor string `json:"suggestor"`
SenderTimestamp time.Time `json:"senderTimestamp"`
PayloadRoot string `json:"payloadRoot"`
KeyType crypto.KeyType `json:"keyType"`
}

Typical usage for a DATA transaction:

input := transaction.ULTransactionInput{
Payload: fmt.Sprintf("test %v %d", wallet.Address, n*i),
From: wallet.Address, // overridden by session for most types
To: wallet.Address,
BlockchainId: blockchainId,
PayloadType: transaction.TX_DATA.String(),
}

Most fields are filled by GenerateTransaction (signature, timestamps, suggestor, key type, and PayloadRoot).

ULTransactionOutput

Fields returned by the node:

type ULTransactionOutput struct {
TransactionId string `json:"transactionId"`
BlockHeight int `json:"blockHeight"`
Clock VectorClock `json:"vectorClock"`
Timestamp Timestamp `json:"timestamp"`
Version string `json:"version"`
Weight int `json:"weight"`
Status string `json:"status"`
Output string `json:"output"`
Proof string `json:"proof"`
ProofVersion string `json:"proofVersion"`
}

ULTransaction

type ULTransaction struct {
ULTransactionInput
ULTransactionOutput
}

Combines both the input fields (what you requested) and the output fields (what the node returned).


Transaction helpers & interfaces

Transaction interface

type Transaction interface {
GetVectorClock() VectorClock
GetTimestamp() Timestamp
GetTransactionId() string
GetTransactionSignatureBody() string
SetTransactionWeight()
}

ULTransaction implements this interface (except GetTransactionSignatureBody, which is not shown in the provided snippet but is part of the conceptual contract).

Methods on *ULTransaction

func (t *ULTransaction) GetVectorClock() VectorClock
func (t *ULTransaction) GetTimestamp() Timestamp
func (t *ULTransaction) GetTransactionId() string
func (t *ULTransaction) SetTransactionWeight()
func (t *ULTransaction) ToBytes() ([]byte, error)
  • GetVectorClock() – returns the causal vector clock for this transaction.
  • GetTimestamp() – returns the Timestamp struct (exact & approximate times).
  • GetTransactionId() – returns the node-assigned transaction ID.
  • SetTransactionWeight() – recomputes and sets t.Weight based on field lengths.
  • ToBytes() – marshals the transaction to JSON bytes.

TransactionFromBytes

func TransactionFromBytes(data []byte) (*ULTransaction, error)

Deserializes a JSON byte slice into a ULTransaction.


Transaction enums & parsing helpers

Status: UL_TransactionStatus

type UL_TransactionStatus int

const (
INVALID_TX_STATUS UL_TransactionStatus = 0
TX_SUBMITTED UL_TransactionStatus = 1
TX_ACCEPTED UL_TransactionStatus = 2
TX_REJECTED UL_TransactionStatus = 3
)

func (ts UL_TransactionStatus) String() string
func ParseTransactionStatus(str string) (UL_TransactionStatus, error)

Type: ULTransactionType

type ULTransactionType int

const (
INVALID_TX_TYPE ULTransactionType = iota
TX_DATA
TX_CREATE_WALLET
TX_ALTER_WALLET
DEPLOY_SMART_CONTRACT
INVOKE_SMART_CONTRACT
UPGRADE_SMART_CONTRACT
ROLLBACK_SMART_CONTRACT
)

func (tt ULTransactionType) String() string
func ParseTransactionType(str string) (ULTransactionType, error)

Common values:

  • TX_DATA – generic data transaction
  • TX_CREATE_WALLET / TX_ALTER_WALLET – wallet-management transactions
  • DEPLOY_SMART_CONTRACT, INVOKE_SMART_CONTRACT, UPGRADE_SMART_CONTRACT, ROLLBACK_SMART_CONTRACT – smart-contract operations

Output: UL_TransactionOutput

type UL_TransactionOutput int

const (
INVALID_TX_OUTPUT UL_TransactionOutput = 0
TO_BE_PROCESSED UL_TransactionOutput = 1
TX_SUCCESS UL_TransactionOutput = 2
TX_REJECTED_BY_DUPLICATE UL_TransactionOutput = 3
TX_REJECTED_BY_UNEXISTING UL_TransactionOutput = 4
TX_REJECTED_BY_DISABLED UL_TransactionOutput = 5
TX_REJECTED_BY_UNAUTHORIZED UL_TransactionOutput = 6
TX_REJECTED_BY_INVALID_SIGNATURE UL_TransactionOutput = 7
TX_TRANSACTION_ERROR UL_TransactionOutput = 8
)

func (tt UL_TransactionOutput) String() string
func ParseTransactionOutput(str string) (UL_TransactionOutput, error)

These values correspond to the string Output field returned in ULTransactionOutput.Output.


Commitments & Merkle trees (advanced)

For advanced use cases where you need manual control over commitments or verification, the SDK exposes helpers on ULTransactionInput and Merkle tree builders.

Commitment helpers on *ULTransactionInput

func (t *ULTransactionInput) GetSignatureCommitment(
hasher hash.Hash,
computeRoot bool,
) (TransactionCommitment, error)

func (t *ULTransactionInput) GetUnboundCommitment(
hasher hash.Hash,
) ([]byte, error)

func (t *ULTransactionInput) HashSignatureCommitment(
hasher hash.Hash,
commitment TransactionCommitment,
) ([]byte, error)

Used internally by GenerateTransaction to:

  • Construct Merkle roots over the payload
  • Bind BlockchainId, From, To, Suggestor, timestamp and payload root into a single commitment hash
  • Produce the data that is ultimately signed by the wallet key

Merkle helpers

func GenerateMerkleTreeWithHardBound(
payload []byte,
modulus *big.Int,
chunkSize int,
depth int,
hasher hash.Hash,
proofIndex uint64,
) ([]byte, [][]byte, []byte, uint64, error)

func GenerateMerkleTree(
payload []byte,
modulus *big.Int,
chunkSize int,
hasher hash.Hash,
proofIndex uint64,
) ([]byte, [][]byte, []byte, uint64, int, error)

These functions:

  • Chunk the payload
  • Build a Merkle tree
  • Return:
    • Merkle root
    • Proof elements
    • The chunk used for proofs
    • Number of leaves
    • (for GenerateMerkleTree) the tree depth

Smart contract payloads & serializer

In addition to standard TX_DATA payloads, the SDK also exposes dedicated types and helpers for interacting with smart contracts, allowing you to model contract calls, upgrades, and rollbacks as JSON payloads that can be submitted through the same transaction flow.

Contract payload structs

type ContractArgs struct {
Value []byte `json:"value"`
}

type InvokeContractPayload struct {
FunctionName string `json:"functionName"`
Args []ContractArgs `json:"args"`
GasLimit uint64 `json:"gasLimit"`
}

type RollbackContractPayload struct {
TargetVersion uint64 `json:"targetVersion"`
RollbackReason string `json:"rollbackReason,omitempty"`
}

type UpgradeContractPayload struct {
NewSourceCode string `json:"newSourceCode"`
UpgradeReason string `json:"upgradeReason,omitempty"`
}

These are meant to be JSON-encoded and placed into ULTransactionInput.Payload when:

  • PayloadType == INVOKE_SMART_CONTRACT.String()
  • PayloadType == UPGRADE_SMART_CONTRACT.String()
  • PayloadType == ROLLBACK_SMART_CONTRACT.String()

Contract VM serializer

The serializer encodes Go values into the binary format expected by the ULedger smart-contract VM.

type ContractDataType byte

const (
TypeNull ContractDataType = 0
TypeBool ContractDataType = 1
TypeInt32 ContractDataType = 2
TypeInt64 ContractDataType = 3
TypeString ContractDataType = 4
TypeBytes ContractDataType = 5
TypeArray ContractDataType = 6
TypeMap ContractDataType = 7
TypeFloat32 ContractDataType = 8
TypeFloat64 ContractDataType = 9
)

func Encode(data interface{}) ([]byte, error)
func Decode(data []byte) (interface{}, error)
func GetType(data []byte) (ContractDataType, error)

At a high level:

  • Encode – takes Go values (bool, int32, string, []byte, map[string]interface{}, []interface{}, etc.) and returns a binary blob for the VM.
  • Decode – reverses that process (primarily useful for tools, tests, or off-chain decoding).
  • GetType – inspects the first byte and returns the encoded ContractDataType.

These tools are primarily used when constructing the arguments for smart-contract calls and will be covered more deeply in a dedicated “Smart contracts” guide.


This page is intended as a reference. For step-by-step guides see our tutorial section.